//+------------------------------------------------------------------+
//|                                                     SpinEdit.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndContainer.h"                     // 容器窗口基类（提供控件组合能力）
#include "Edit.h"                             // 编辑框类（用于显示当前数值）
#include "BmpButton.h"                        // 位图按钮类（用于增减按钮）

//+------------------------------------------------------------------+
//| 资源定义：数字调节控件所需的位图资源                               |
//+------------------------------------------------------------------+
#resource "res\\SpinInc.bmp"                 // 增量按钮图片（向上箭头）
#resource "res\\SpinDec.bmp"                 // 减量按钮图片（向下箭头）

//+------------------------------------------------------------------+
//| CSpinEdit 类：MQL5 数字调节控件（带增减按钮的编辑框）               |
//| 核心能力：结合编辑框与两个方向按钮，支持通过点击按钮调整整数数值，    |
//|           可设置数值范围，自动限制输入在有效区间内，适用于参数调节    |
//| 适用场景：需要用户输入整数且有明确范围的场景（如数量、周期、阈值等）   |
//+------------------------------------------------------------------+
class CSpinEdit : public CWndContainer
  {
private:
   // 子控件（私有，仅内部管理）
   CEdit             m_edit;                // 编辑框（显示当前数值，只读）
   CBmpButton        m_inc;                 // 增量按钮（点击增加数值）
   CBmpButton        m_dec;                 // 减量按钮（点击减少数值）

   // 数值范围参数（私有，确保设置时自动校验）
   int               m_min_value;           // 最小值（默认 0）
   int               m_max_value;           // 最大值（默认 0）

   // 当前状态（私有，确保修改时触发事件）
   int               m_value;               // 当前数值（默认 0，范围：m_min_value ~ m_max_value）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化数字调节控件默认状态
    * @details 初始化数值范围（最小/最大/当前值均为 0），子控件待 Create 时创建
    */
                     CSpinEdit(void);

   /**
    * @brief 析构函数：清理数字调节控件资源
    * @details 依赖父类 CWndContainer 的析构逻辑，自动释放子控件（编辑框、增减按钮）
    */
                    ~CSpinEdit(void);

   //----------------------------------------------------------------
   // 控件创建：初始化数字调节控件及其子控件
   //----------------------------------------------------------------
   /**
    * @brief 创建数字调节控件（编辑框+增减按钮）
    * @param chart [in] 目标图表ID（0 表示当前活跃图表）
    * @param name [in] 控件唯一标识名（图表内不可重复）
    * @param subwin [in] 绑定的子窗口编号（0 = 主窗口，≥1 = 指标子窗口）
    * @param x1 [in] 左上角X坐标（像素，相对于图表窗口）
    * @param y1 [in] 左上角Y坐标（像素）
    * @param x2 [in] 右下角X坐标（像素）
    * @param y2 [in] 右下角Y坐标（像素）
    * @return bool - 创建结果：true=成功（父类初始化+子控件创建完成），false=失败
    * @note 1. 控件高度不能小于系统最小值（CONTROLS_SPIN_MIN_HEIGHT）；
    *       2. 编辑框默认只读，通过按钮调整数值
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   //----------------------------------------------------------------
   // 事件处理：响应数字调节控件相关事件
   //----------------------------------------------------------------
   /**
    * @brief 处理数字调节控件事件（按钮点击、数值变化等）
    * @param id [in] 事件ID（如 ON_CLICK、ON_CHANGE 等）
    * @param lparam [in] 长整数参数（事件相关数据）
    * @param dparam [in] 双精度参数（事件相关数据）
    * @param sparam [in] 字符串参数（通常为控件名称，用于识别事件来源）
    * @return bool - 处理结果：true=事件已处理，false=未处理（交由父类处理）
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 数值范围配置：设置/获取最小/最大允许值
   //----------------------------------------------------------------
   /**
    * @brief 获取最小值
    * @return int - 最小值（默认 0）
    */
   int               MinValue(void) const;

   /**
    * @brief 设置最小值
    * @param value [in] 目标最小值（≤ m_max_value）
    * @note 设置后会自动调整当前值（若 m_value < value，强制设为 value）
    */
   void              MinValue(const int value);

   /**
    * @brief 获取最大值
    * @return int - 最大值（默认 0）
    */
   int               MaxValue(void) const;

   /**
    * @brief 设置最大值
    * @param value [in] 目标最大值（≥ m_min_value）
    * @note 设置后会自动调整当前值（若 m_value > value，强制设为 value）
    */
   void              MaxValue(const int value);

   //----------------------------------------------------------------
   // 当前数值控制：设置/获取当前数值
   //----------------------------------------------------------------
   /**
    * @brief 获取当前数值
    * @return int - 当前数值（范围：m_min_value ~ m_max_value）
    */
   int               Value(void) const;

   /**
    * @brief 设置当前数值
    * @param value [in] 目标数值（自动被限制在 m_min_value ~ m_max_value 范围内）
    * @return bool - 设置结果：true=数值发生变化，false=数值未变化
    * @note 数值变化时会更新编辑框显示，并触发 ON_CHANGE 事件
    */
   bool              Value(int value);

   //----------------------------------------------------------------
   // 状态序列化：保存/加载当前数值到文件
   //----------------------------------------------------------------
   /**
    * @brief 将当前数值保存到文件
    * @param file_handle [in] 文件句柄（需提前以 FILE_WRITE 模式打开）
    * @return bool - 保存结果：true=成功（数值写入文件），false=失败（文件无效或写入错误）
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从文件加载数值（恢复当前值）
    * @param file_handle [in] 文件句柄（需提前以 FILE_READ 模式打开）
    * @return bool - 加载结果：true=成功（从文件读取值并设置当前值），false=失败
    */
   virtual bool      Load(const int file_handle);

protected:
   //----------------------------------------------------------------
   // 子控件创建：创建编辑框和按钮（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建编辑框（用于显示当前数值）
    * @return bool - 创建结果：true=成功（编辑框初始化+设为只读+添加到容器），false=失败
    */
   virtual bool      CreateEdit(void);

   /**
    * @brief 创建增量按钮（上箭头按钮，位于控件右侧上方）
    * @return bool - 创建结果：true=成功（按钮位置、图片、点击属性配置完成），false=失败
    */
   virtual bool      CreateInc(void);

   /**
    * @brief 创建减量按钮（下箭头按钮，位于控件右侧下方）
    * @return bool - 创建结果：true=成功（按钮位置、图片、点击属性配置完成），false=失败
    */
   virtual bool      CreateDec(void);

   //----------------------------------------------------------------
   // 按钮事件回调：处理增减按钮点击（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 增量按钮点击事件回调（点击后当前数值+1）
    * @return bool - 处理结果：true=成功（数值更新+事件通知），false=失败
    */
   virtual bool      OnClickInc(void);

   /**
    * @brief 减量按钮点击事件回调（点击后当前数值-1）
    * @return bool - 处理结果：true=成功（数值更新+事件通知），false=失败
    */
   virtual bool      OnClickDec(void);

   //----------------------------------------------------------------
   // 数值变化回调：数值更新时触发（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 数值变化事件回调（同步编辑框显示+发送事件）
    * @return bool - 处理结果：true=成功（编辑框文本更新+发送 ON_CHANGE 事件），false=失败
    */
   virtual bool      OnChangeValue(void);
  };

//+------------------------------------------------------------------+
//| CSpinEdit 事件映射：关联子控件事件到处理函数（用于IDE智能提示）      |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CSpinEdit)
   ON_EVENT(ON_CLICK, m_inc, OnClickInc)    // 增量按钮点击 → 调用 OnClickInc
   ON_EVENT(ON_CLICK, m_dec, OnClickDec)    // 减量按钮点击 → 调用 OnClickDec
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+